package com.sun.managementsystemsimulationhomeworkcode.chapter2.main;

import com.sun.managementsystemsimulationhomeworkcode.chapter2.init.JobProcess;
import com.sun.managementsystemsimulationhomeworkcode.chapter2.init.ProcessJobResult;
import com.sun.managementsystemsimulationhomeworkcode.chapter2.pojo.Group;
import com.sun.managementsystemsimulationhomeworkcode.chapter2.pojo.Job;
import com.sun.managementsystemsimulationhomeworkcode.chapter2.pojo.MyMachine;
import com.sun.managementsystemsimulationhomeworkcode.chapter2.pojo.MySystem;
import org.springframework.boot.autoconfigure.batch.BatchProperties;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;


/**
 * 应用类
 *
 * @author Haoran Sun
 * @since 2024/09/18
 */


public class Application {


    private static final double TIME_LIMIT = 240;

    public static void main(String[] args) {

        // 初始化系统
        MySystem mySystem = MySystem.builder()
                .jobInProcess(0)
                .groups(new ArrayList<>())
                .build();
        // 初始化各组状态
        // A组
        Group groupA = Group.builder()
                .jobs(new ArrayList<>())
                .machines(new ArrayList<>())
                .type(1)
                .count(0)
                .max(4)
                .build();
        // B组
        Group groupB = Group.builder()
                .jobs(new ArrayList<>())
                .machines(new ArrayList<>())
                .type(2)
                .count(0)
                .max(Integer.MAX_VALUE)
                .build();
        // 机器初始化
        // 1号机器
        MyMachine machine1 = MyMachine.builder()
                .id(1)
                .status(1)
                .workTime(0)
                .build();
        // 2号机器
        MyMachine machine2 = MyMachine.builder()
                .id(2)
                .status(1)
                .workTime(0)
                .build();
        // 3号机器
        MyMachine machine3 = MyMachine.builder()
                .id(3)
                .status(1)
                .workTime(0)
                .build();
        mySystem.getGroups().add(groupA);
        mySystem.getGroups().add(groupB);
        groupA.getMachines().add(machine1);
        groupA.getMachines().add(machine2);
        groupB.getMachines().add(machine3);

        // 初始化任务
        List<Job> jobs = new ArrayList<>();
        JobProcess.initJob(jobs);

        // 初始化模拟时钟
        double time = 0;

        // 模拟中已完成的工件
        List<Job> finishedJobs = new ArrayList<>();

        // 模拟终止条件为模拟时钟大于240小时后
        while (!(time > TIME_LIMIT) ) {
            // 模拟时钟推进
            ProcessJobResult result = JobProcess.processJob(jobs, mySystem, time);
            time = result.getTime();
            if (result.getType() == 1 && !jobs.isEmpty()) {
                // 工件进入系统
                Job job = jobs.remove(0);
                int countA = groupA.getCount();
                if (countA < groupA.getMax()) {
                    // 工件进入A组
                    // 这里进入A组可以根据工件类型计算出需的加工时间
                    if (job.getType() == 1) {
                        JobProcess.a1ProcessTimeSetter(job);
                    } else {
                        JobProcess.a2ProcessTimeSetter(job);
                    }
                    groupA.setCount(countA + 1);
                    if (machine1.getStatus() == 1 && machine2.getStatus() == 1) {
                        //两个机器均空闲  工件 0.35 概率进入机器1；  0.65 概率进入机器2。
                        job.setStartTime(time);
                        job.setEndTime(time + job.getProcessTime());

                        if (new Random().nextDouble() < 0.35) {
                            machine1.setStatus(2);
                            machine1.setJob(job);
                        } else {
                            machine2.setStatus(2);
                            machine2.setJob(job);
                        }
                    } else if (machine1.getStatus() == 1) {
                        job.setStartTime(time);
                        job.setEndTime(time + job.getProcessTime());
                        machine1.setStatus(2);
                        machine1.setJob(job);
                    } else if (machine2.getStatus() == 1) {
                        job.setStartTime(time);
                        job.setEndTime(time + job.getProcessTime());
                        machine2.setStatus(2);
                        machine2.setJob(job);
                    } else {
                        // 组内机器均为工作状态
                        groupA.getJobs().add(job);
                    }
                } else {
                    // 工件进入B组
                    JobProcess.bProcessTimeSetter(job);
                    groupB.setCount(groupB.getCount() + 1);
                    if (machine3.getStatus() == 1) {
                        // 机器空闲
                        job.setStartTime(time);
                        job.setEndTime(time + job.getProcessTime());
                        machine3.setStatus(2);
                        machine3.setJob(job);
                    } else {
                        // 机器工作中
                        groupB.getJobs().add(job);
                    }
                }
            } else {
                // 工件离开系统
                if (result.getMachineId() == 3) {
                    // B组的3号机器完成工件
                    Job job = machine3.getJob();
                    machine3.setJob(null);
                    machine3.setWorkTime(machine3.getWorkTime() + job.getProcessTime());
                    finishedJobs.add(job);
                    // 更新系统的工件的时间积分值
                    mySystem.setJobInProcess(mySystem.getJobInProcess() + job.getEndTime() - job.getArriveTime());
                    groupB.setCount(groupB.getCount() - 1);
                    // 判断B组是否还有工件
                    if (!groupB.getJobs().isEmpty()) {
                        // B组有工件，则取出第一个工件，开始加工
                        Job job1 = groupB.getJobs().remove(0);
                        job1.setStartTime(time);
                        job1.setEndTime(time + job1.getProcessTime());
                        machine3.setJob(job1);
                    } else {
                        // B组没有工件
                        machine3.setStatus(1);
                    }
                } else {
                    // A组机器完成工件
                    groupA.setCount(groupA.getCount() - 1);
                    // 判断是哪一台机器完成了工件
                    if (result.getMachineId() == 1) {
                        // 1号机器完成工件
                        Job job = machine1.getJob();
                        machine1.setJob(null);
                        machine1.setWorkTime(machine1.getWorkTime() + job.getProcessTime());
                        finishedJobs.add(job);
                        // 更新系统的工件的时间积分值
                        mySystem.setJobInProcess(mySystem.getJobInProcess() + job.getEndTime() - job.getArriveTime());
                        // 判断A组是否还有工件
                        List<Job> jobsA = groupA.getJobs();
                        if (!jobsA.isEmpty()) {
                            // A组有工件，则取出工件加工时间最短的工件，开始加工
                            Job job1 = jobsA.stream().min(Comparator.comparing(Job::getProcessTime)).get();
                            jobsA.remove(job1);
                            job1.setStartTime(time);
                            job1.setEndTime(time + job1.getProcessTime());
                            machine1.setJob(job1);
                        } else {
                            machine1.setStatus(1);
                        }
                    } else {
                        // 2号机器完成工件
                        Job job = machine2.getJob();
                        machine2.setJob(null);
                        machine2.setWorkTime(machine2.getWorkTime() + job.getProcessTime());
                        finishedJobs.add(job);
                        // 更新系统的工件的时间积分值
                        mySystem.setJobInProcess(mySystem.getJobInProcess() + job.getEndTime() - job.getArriveTime());
                        // 判断A组是否还有工件
                        List<Job> jobsA = groupA.getJobs();
                        if (!jobsA.isEmpty()) {
                            // A组有工件，则取出工件加工时间最短的工件，开始加工
                            Job job1 = jobsA.stream().min(Comparator.comparing(Job::getProcessTime)).get();
                            jobsA.remove(job1);
                            job1.setStartTime(time);
                            job1.setEndTime(time + job1.getProcessTime());
                            machine2.setJob(job1);
                        } else {
                            machine2.setStatus(1);
                        }
                    }
                }
            }
        }


        // 处理模拟终止
        // 处理工件的时间积分
        Job job1 = machine1.getJob();
        Job job2 = machine2.getJob();
        Job job3 = machine3.getJob();
        if (job1 != null) {
            mySystem.setJobInProcess(mySystem.getJobInProcess() + TIME_LIMIT - job1.getArriveTime());
        }
        if (job2 != null) {
            mySystem.setJobInProcess(mySystem.getJobInProcess() + TIME_LIMIT - job2.getArriveTime());
        }
        if (job3 != null) {
            mySystem.setJobInProcess(mySystem.getJobInProcess() + TIME_LIMIT - job3.getArriveTime());
        }


        List<Job> jobsA = groupA.getJobs();
        List<Job> jobsB = groupB.getJobs();
        if (!jobsA.isEmpty()) {
            jobsA.forEach(
                    job -> mySystem.setJobInProcess(mySystem.getJobInProcess() + TIME_LIMIT - job.getArriveTime())
            );
        }

        if (!jobsB.isEmpty()) {
            jobsB.forEach(
                    job -> mySystem.setJobInProcess(mySystem.getJobInProcess() + TIME_LIMIT - job.getArriveTime())
            );
        }

        System.out.println("系统的工件平均停留数：" + mySystem.getJobInProcess() / TIME_LIMIT);
        System.out.println("机器1的负荷率" + machine1.getWorkTime() / TIME_LIMIT);
        System.out.println("机器2的负荷率" + machine2.getWorkTime() / TIME_LIMIT);
        System.out.println("机器2的负荷率" + machine2.getWorkTime() / TIME_LIMIT);
        // 1类工件的已完成工件的集合
        ArrayList<Job> jobs1 = new ArrayList<>();
        // 2类工件的已完成工件的集合
        ArrayList<Job> jobs2 = new ArrayList<>();
        finishedJobs.forEach(
                job -> {
                    if (job.getType() == 1){
                        jobs1.add(job);
                    } else {
                        jobs2.add(job);
                    }
                }
        );
        System.out.println("1类工件的平均加工周期：" + jobs1.stream().mapToDouble(Job::getProcessTime).sum()/jobs1.size());
        System.out.println("2类工件的平均加工周期：" + jobs2.stream().mapToDouble(Job::getProcessTime).sum()/jobs2.size());

    }


}
